//codigo das maquinas nivel 1
#include<stdlib.h>
#include<stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>

#define TAMBUFFER 1000
#define NUMTOT 125
#define MAX 10000
#define TAMBUFFERFIN 4000
#define PORT 4234

double inicializaCliente(int*, int*, int);
void converteIntToChar(int*, char*);
void enviaDadosServidor(char*, int, char*);
double recebeDadosCliente(int, char*);

int main(int argc, char **argv)
{
	int *vetorOriginal, *vetorOrdenado;
	int i;
	char *dadosAEnviar;
	double tempoDeOrdenacao;
	char *dadosFinais;
	double tempoDeTransmissao;
	float tempoTotal =0;
	clock_t startTime;
	
	
	if(argc < 3)
	{
		printf("Voce usou incorretamente os parametros: host, port\n");
		exit(1);
	}
	
	//---------------------------------------------------inicio tempo total
	startTime = clock();
	
	vetorOriginal = (int*) malloc(NUMTOT*sizeof(int));
	vetorOrdenado = (int*) malloc(NUMTOT*sizeof(int));
	tempoDeOrdenacao = inicializaCliente(vetorOriginal, vetorOrdenado, atoi(argv[2]));
	//imprime tempo de ordenacao
	printf("Tempo de ordenacao: %f\n", tempoDeOrdenacao);
	//envia dados para servidor pai
	dadosAEnviar = (char*) malloc(TAMBUFFER*sizeof(char));
	converteIntToChar(vetorOrdenado, dadosAEnviar);
	enviaDadosServidor(argv[1], atoi(argv[2]), dadosAEnviar);	
	
	//------------------------------------------------------recebe resultado final
	dadosFinais = (char*) malloc((TAMBUFFERFIN*2)*sizeof(char));
	strcpy(dadosFinais, "\0");
	tempoDeTransmissao = recebeDadosCliente(PORT, dadosFinais);
	printf("\nResultado Final: %s\n", dadosFinais);	
	printf("\nTempo transmissao: %lf sec\n", tempoDeTransmissao);
	
	tempoTotal = (float)(clock()-startTime)/CLOCKS_PER_SEC;
	printf("\nTempo total da operacao: %f sec\n", tempoTotal);
	//--------------------------------------------------fim tempo total
	
	free(vetorOrdenado);
	free(vetorOriginal);
	free(dadosAEnviar);
	free(dadosFinais);
	return 0;
}

double recebeDadosCliente(int port, char* dados)
{
	int sockfd, newsockfd, portno;
	socklen_t clilen;
	char *buffer;
	struct sockaddr_in serv_addr, cli_addr;
	int n;
	clock_t startTime;
	double tempo;
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("Erro na criacao do socket\n");
	}
	
	bzero((char*) &serv_addr, sizeof(serv_addr));
	portno = port;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(portno);
	
	if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("Erro no bind");
	}
	else
	{
		printf("Aguardando conexao\n");
	}
	
	listen(sockfd, 5);
	clilen = sizeof(cli_addr);
	newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
	if(newsockfd < 0)
	{
		printf("Erro ao aceitar\n");
	}
	else
	{
		printf("Aceitou conexao\n");
	}
	
	buffer = (char*) malloc((TAMBUFFERFIN*2)*sizeof(char));
	//------------------------------------------------tempo de transmissao
	startTime = clock();
	n = read(newsockfd, buffer, (TAMBUFFERFIN*2));
	tempo = (double)(clock()-startTime)/CLOCKS_PER_SEC;
	//-------------------------------------------------fim tempo de transmissao
	if(n < 0)
	{
		printf("Erro ao ler socket\n");
	}
	
	strcpy(dados, buffer);
	close(sockfd);
	close(newsockfd);
	free(buffer);
	return tempo;
}

double inicializaCliente(int* vetorOriginal, int* vetorOrdenado, int port) //inicializa dados
{
	int i, j, aux;
	double tempo;
	clock_t startTime;
	
	srand(port);
	for(i=0; i< NUMTOT; i++)
	{		
		vetorOriginal[i] = rand()%MAX;
		vetorOrdenado[i] = vetorOriginal[i];
	}
	//inicio tempo de ordenacao
	startTime = clock();
	for(i=0; i<NUMTOT; i++)
	{
		for(j=0; j<NUMTOT-1; j++)
		{
			if(vetorOrdenado[j] > vetorOrdenado[j+1])
			{
				aux = vetorOrdenado[j];
				vetorOrdenado[j] = vetorOrdenado[j+1];
				vetorOrdenado[j+1] = aux; 
			}
		}
	}
	tempo =(double)(clock()-startTime)/CLOCKS_PER_SEC;
	//fim tempo de ordenacao
	
	for(i=0; i<NUMTOT; i++)
	{
		printf("%d,", vetorOrdenado[i]);
	}
	printf("\n");
	
	return tempo;
}

void converteIntToChar(int* vetorInt, char* vetorChar) //converte vetor de int para vetor de char para enviar para servidor pai
{
	int i;
	char *buffer = (char*) malloc((TAMBUFFER*2)*sizeof(char));
	char str[15];
	
	strcpy(buffer, "\0");
	strcpy(str, "\0");
	for(i=0; i< NUMTOT; i++)
	{
		sprintf(str, "%d ", vetorInt[i]);
		strcat(buffer, str);
		strcpy(str, "\0");
	}
	strcat(buffer, "\0");
	strcpy(vetorChar, buffer);
	free(buffer);
}

void enviaDadosServidor(char* host, int port, char* dados) //envia dados para servidor pai
{
	int sockfd, portno = port, n;
	struct sockaddr_in serv_addr;
	struct hostent *server;
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("Erro no socket\n");
		exit(1);
	}
	
	server = gethostbyname(host);
	if(server == NULL)
	{
		printf("Erros no host\n");
		exit(1);
	}
	
	bzero((char*) &serv_addr, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	bcopy((char*) server->h_addr, (char*)&serv_addr.sin_addr.s_addr, server->h_length);
	serv_addr.sin_port = htons(portno);
	
	if(connect(sockfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("Erro na conexao");
		exit(1);
	}
	
	n = write(sockfd, dados, strlen(dados));
	if(n < 0)
	{
		printf("Erro de escrita em socket\n");
		exit(1);
	}
	close(sockfd);
}
